<!--
@description    自定义筛选条件
@author         秦俊强
@email          458112865@qq.com
@create         2021-06-13


@Examples & Step

1. import CustomScreen from './customScreen';

2. components: { CustomScreen }

3. 使用 customScreenRef 可自定义
   下面是 2 种使用方法示例（* 详细请查看 192 行 props 里面的说明）

    3.1 默认空，手动添加自定义筛选项
    <CustomScreen ref="customScreenRef"></CustomScreen>

    3.2 回填信息，编辑漏斗时，默认填充数据
    <CustomScreen ref="customScreenRef" :supName="'$AppClick'"
                  :editArr="{ conditions: [ 'field': '', 'function': '', "params": [] ], relation: 'or' }"></CustomScreen>

4. 添加一行
    => this.$refs.customScreenRef.editCond();

5. 返回传参需要的 filter 对象
    => this.$refs.customScreenRef.getFilterConditions();
-->

<template>
  <div class="viewFunnelBox" :style="{ padding: '5px 0' }" v-if="arrSetting.length > 0">

    <!-- 【且】【或】切换 -->
    <div class="andOrNotBox" v-if="arrSetting.length > 1"
         @click="switchRelation">{{ relation.name }}
    </div>

    <!-- 线 -->
    <div class="lineBox" :style="{ height: getLineHeight() }"
         v-if="arrSetting.length > 1"></div>

    <!-- 动态添加自定义筛选项 start -->
    <div class="funnelSettingBox" v-for="(item, i) in arrSetting" :key="i">

      <!-- 1. 一级（主）下拉选项 start -->
      <el-select size="mini" @change="settingChange(i)" placeholder="请选择"
                 :title="arrSetting[i].cname"
                 filterable value-key="name"
                 v-model="arrSetting[i]">
        <el-option v-for="cItem in levelOneOpts"
                   :key="cItem.name" :value="cItem" :disabled="cItem.isDisabled"
                   :style="{ 'max-width': '600px' }"
                   :label="cItem.cname" :title="cItem.cname"></el-option>
      </el-select>
      <!-- 1. 一级（主）下拉选项 end -->


      <!-- 2. 二级下拉选项，根据（一级）不同的 data_type 显示不同的下拉选项 start -->
      <el-select size="mini" :style="{ width: '150px' }"
                 v-if="arrSetting[i] && arrSetting[i].name"
                 v-model="arrSetting[i]['new_data_type']" value-key="key"
                 @change="dataTypeChange(i)">
        <el-option v-for="cItem in getDataTypeOpts(i)"
                   :key="cItem.key" :value="cItem" :label="cItem.name"></el-option>
      </el-select>
      <!-- 2. 二级下拉选项，根据（一级）不同的 data_type 显示不同的下拉选项 end -->


      <!-- 3.1 可输入多个值（数字或字符串）start -->
      <el-select v-if="showLeaf(i, 'createCommon')" size="mini" placeholder="输入内容后，按回车可添加多个"
                 v-model="arrSetting[i]['customArr']" :style="{ width: '40%' }"
                 @change="$forceUpdate()"
                 multiple filterable allow-create default-first-option clearable>
        <el-option v-for="(cItem, ind) in lastOptsMap[item.name]"
                   :key="cItem" :value="cItem" :label="cItem"></el-option>
      </el-select>
      <!-- 3.1 可输入多个值（数字或字符串）end -->

      <!-- 3.2 可输入单个值 start -->
      <el-input v-if="showLeaf(i, 'inputCommon')" size="mini" placeholder="请输入内容"
                v-model="arrSetting[i]['customStr']" :style="{ width: '40%' }" clearable></el-input>
      <!-- 3.2 可输入单个值 end -->

      <!-- 3.3 数字区间 start -->
      <div class="betweenBox" v-if="showLeaf(i, 'numBetween')">
        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumBetween_0']"
                  :style="{ width: '110px' }" clearable></el-input>

        <span style="padding: 0 5px;">与</span>

        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumBetween_1']"
                  :style="{ width: '110px' }" clearable></el-input>

        <span style="padding: 0 5px;">之间</span>
      </div>
      <!-- 3.3 数字区间 end -->

      <!-- 3.4.1 日期区间 yyyy-mm-dd 00:00 至 yyyy-mm-dd 00:00 -->
      <el-date-picker v-if="showLeaf(i, 'autoDateBetween')"
                      format="yyyy-MM-dd 00:00" value-format="yyyy-MM-dd 00:00"
                      type="daterange" size="mini" range-separator="至"
                      start-placeholder="开始日期" end-placeholder="结束日期"
                      :picker-options="pickerOptions" style="width: 280px;"
                      v-model="arrSetting[i]['customAutoDateBetween']"></el-date-picker>

      <!-- 3.4.2 相对当前时间点，在 n 天 以内/以外 -->
      <div class="datetimeBox" v-if="showLeaf(i, 'relativeWithin')">
        <span class="size">在</span>

        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumDate']"
                  :style="{ width: '100px', paddingRight: '5px' }" clearable></el-input>

        <span class="size">天</span>

        <el-select size="mini" :style="{ width: '90px' }"
                   v-model="arrSetting[i]['customRelative']" value-key="key"
                   @change="$forceUpdate()">
          <el-option v-for="cItem in datetimeOpts[1].arr"
                     :key="cItem.key" :value="cItem" :label="cItem.name"></el-option>
        </el-select>
      </div>

      <!-- 3.4.3 相对当前时间区间，在过去xx到过去xx之内 -->
      <div class="datetimeBox" v-if="showLeaf(i, 'dayBetween')">
        <span class="size">在过去</span>

        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumDate_0']"
                  :style="{ width: '100px', paddingRight: '5px' }" clearable></el-input>

        <span class="size">天到过去</span>

        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumDate_1']"
                  :style="{ width: '100px', paddingRight: '5px' }" clearable></el-input>

        <span class="size">天之内</span>
      </div>

      <!-- 3.4.4 相对当前事件发生时间 在【之前/后/当天/当周/当月】的【n】【天/时/分/秒】之内 -->
      <div class="datetimeBox" v-if="showLeaf(i, 'eventTime')">
        <span class="size">在</span>

        <el-select size="mini" :style="{ width: '110px' }"
                   v-model="arrSetting[i]['customEventTime']" value-key="key"
                   @change="$forceUpdate()">
          <el-option v-for="cItem in relativeEventTime"
                     :key="cItem.key" :value="cItem" :label="cItem.name"></el-option>
        </el-select>

        <span>
          <span class="size">的</span>

          <el-input size="mini" type="number" placeholder="请输入数字"
                    v-model="arrSetting[i]['customNumDate_2']"
                    :style="{ width: '100px', paddingRight: '5px' }" clearable></el-input>

          <el-select size="mini" :style="{ width: '90px' }"
                     v-model="arrSetting[i]['customTimeUnit']" value-key="key"
                     @change="$forceUpdate()">
            <el-option v-for="cItem in timeUnit" :key="cItem.key" :value="cItem" :label="cItem.name"></el-option>
          </el-select>

          <span>之内</span>
        </span>
      </div>


      <!-- 移除筛选项 -->
      <i class="el-icon-delete" title="移除筛选项" @click="editCond(i)"></i>

    </div>
    <!-- 动态添加自定义筛选项 end -->

  </div>
</template>


<script>
/* dataType 类型配置 */
import DataTypeConfig from './dataType.config.js';

/**
 * api 接口
 * */
import {propertyList, valueList} from './attribution';


export default {
  name: 'custom-screen',

  props: {
    /**
     * 是否是事件类型 默认为是
     * 如果不是则为用户类型
     * */
    isEvent: {
      type: Boolean,
      default: () => {
        return true;
      }
    },

    /**
     * 是否有父级（默认无，可直接调用全部接口）
     * 如果有，则需要传下面的 supName 参数才能调用接口
     * */
    isSupName: {
      type: Boolean,
      default: () => {
        return false;
      }
    },

    /**
     * 上级 name，如：'$AppClick'
     * 用于创建/编辑漏斗时，根据上级 name 动态获取子级下拉选项
     *
     * 可传，可不传（默认空）
     * */
    supName: {
      type: String,
      default: () => {
        return '';
      }
    },

    /**
     * 编辑漏斗时需要传的参数，用于回填信息
     * 注意：编辑漏斗时，上面的 supName 字段必传
     * 默认值 { conditions: [], relation: '' }
     * */
    editArr: {
      type: Object,
      default: () => {
        return {
          conditions: [
            /*{ "field": "$distinct_id", "function": "equal", "params": ['a', 'b', 'c'] },
            { "field": "$time", "function": "absolute_between", "params": ["2021-06-01 00:00", "2021-06-09 00:00"] },
            { "field": "$element_position", "function": "notContain", "params": "100" },*/
          ],

          relation: 'or',       // 且 and | 或 or，conditions length 大于 1 时 relation 不可为空
        };
      }
    }
  },

  data() {
    return {
      /* 一级下拉项 */
      levelOneOpts: [],

      /* 叶子节点的下拉选项 */
      lastOptsMap: {},

      /* data_type 为 bool 时选，没有 3 级信息 */
      boolOpts: DataTypeConfig.boolOpts,

      /* data_type 为 string 时选 */
      textOpts: DataTypeConfig.textOpts,

      /* data_type 为 number 时选 */
      numberOpts: DataTypeConfig.numberOpts,

      /* data_type 为 datetime 时选  */
      datetimeOpts: DataTypeConfig.datetimeOpts,

      /* data_type 为 list 时选 */
      listOpts: DataTypeConfig.listOpts,

      /* 且 and | 或 or */
      relation: {key: 'and', name: '且'},

      /* 日期选择器，不能选择今天以后的日期 */
      pickerOptions: {
        disabledDate(time) {
          return time.getTime() > Date.now() - 8.64e6;
        }
      },

      /* 相对事件发生时间 选项 */
      relativeEventTime: DataTypeConfig.relativeEventTime,

      /* 时间单位 选项 */
      timeUnit: DataTypeConfig.timeUnit,

      /* 自定义筛选 */
      arrSetting: [],

    }
  },

  created() {
    let t = this;
    t.getFunnelCondition();

    /* 监听 supName 变化 */
    t.$watch('supName', () => {
      console.log('****** supName is change，重置自定义筛选项，根据 supName 的值获取对应的子级下拉列表');
      t.arrSetting = [];
      t.getFunnelCondition();
    });
  },

  methods: {

    /* 回填 数据 */
    initData() {
      let t = this;
      let conditions = t.editArr.conditions;
      let relation = t.editArr.relation;
      for (let i = 0; i < conditions.length; i++) {
        let item = conditions[i];

        t.editCond();
        t.initLevelOne(item, i);
      }

      t.switchRelation(relation);
      t.initDisabled();

      setTimeout(() => {
        this.$forceUpdate();
      });
    },

    /* 回填 一级下拉选项 */
    initLevelOne(item, ind) {
      for (let i = 0; i < this.levelOneOpts.length; i++) {
        let _item = this.levelOneOpts[i];

        let f = item.field, n = _item.name;
        let fArr = f.split(".");
        let nArr = n.split(".");

        if (fArr[fArr.length - 1] === nArr[nArr.length - 1]) {
          this.arrSetting[ind] = _item;
          this.initLevelTwo(item, ind);
          return;
        }
      }
    },

    /* 回填 二级下拉菜单 */
    initLevelTwo(item, ind) {
      let opts = this.getDataTypeOpts(ind);

      for (let i = 0; i < opts.length; i++) {
        let _item = opts[i];

        if (item['function'] === _item.key) {
          this.arrSetting[ind]['new_data_type'] = _item;

          this.initLevelThree(item, ind);
          return;
        }
      }
    },

    /* 回填 三级下拉菜单 */
    initLevelThree(item, ind) {
      let _item = this.arrSetting[ind];
      let objMap = DataTypeConfig.rules;

      for (let key in objMap) {
        let obj = objMap[key];

        let arr1 = obj.dataTypeArr;
        let arr2 = obj.newDataTypeArr;

        if (arr1.indexOf(_item.dataType) >= 0 && arr2.indexOf(_item['new_data_type'].key) >= 0) {

          if (obj.key === 'customArr') {
            this.getValueList(ind, item.params);
            return;
          }

          this.arrSetting[ind][obj.key] = item.params;
          return;

        }
      }
    },

    /* 监听一级（主）筛选条件项 */
    settingChange(i) {
      this.initCustomVal(i);
      this.initDisabled();

      this.getValueList(i);

      this.$forceUpdate();  // 强制刷新组件数据
    },

    /* 监听二级下拉筛选 */
    dataTypeChange(i) {
      let obj = this.arrSetting[i];
      console.log('监听二级筛选项 = ', i, obj);

      this.initCustomVal(i);

      this.$forceUpdate();  // 强制刷新组件数据
    },

    /* 切换【且】【或】 */
    switchRelation(val) {
      let valMap = {
        or: {key: 'or', name: '或'},
        and: {key: 'and', name: '且'},
      };

      if (val && valMap[val]) {
        this.relation = valMap[val];
        return;
      }

      let key = this.relation.key;
      this.relation = (key === 'and') ? {key: 'or', name: '或'} : {key: 'and', name: '且'};
    },

    /* 判断显示哪个三级选项 */
    showLeaf(i, str) {
      let obj = this.arrSetting[i];
      let dataType = obj['dataType'];                 // 一级 type
      let newDataType = obj['new_data_type'];         // 二级 type

      // 如果没有选择一级或二级，那么就隐藏三级
      if (!dataType || !newDataType || !newDataType.key) {
        return false;
      }

      // 显示条件
      let objMap = DataTypeConfig.rules;

      // 可自定义多个值，敲回车进行添加值 的组件
      if (objMap[str]) {
        let dataTypeArr = objMap[str].dataTypeArr;
        let newDataTypeArr = objMap[str].newDataTypeArr;

        return (dataTypeArr.indexOf(dataType) >= 0) && (newDataTypeArr.indexOf(newDataType.key) >= 0);
      }

      return false;
    },

    /* 添加 add | 移除 remove 筛选条件 */
    editCond(i) {
      // 移除筛选条件
      if (typeof i === 'number') {
        this.arrSetting.splice(i, 1);
        this.initDisabled();
        return;
      }

      // 添加筛选项
      this.arrSetting.push({});
      this.initCustomVal();

      // 默认【且】
      if (this.arrSetting.length === 2) {
        this.relation = {key: 'and', name: '且'};
      }
    },

    /* 初始化自定义字段（三级项）的值 */
    initCustomVal(ind) {
      let t = this;

      setTimeout(() => {
        let arrSetting = t.arrSetting;

        let _ind = (typeof ind === 'number') ? ind : (arrSetting.length - 1);

        if (arrSetting[_ind]['customArr'] && arrSetting[_ind]['customArr'].length > 0) {
          t.arrSetting[_ind]['customArr'] = [];    //数组
        }

        if (arrSetting[_ind]['customStr']) {
          t.arrSetting[_ind]['customStr'] = '';    //对象
        }

        if (arrSetting[_ind]['customNumBetween_0'] || arrSetting[_ind]['customNumBetween_1']) {
          t.arrSetting[_ind]['customNumBetween_0'] = '';
          t.arrSetting[_ind]['customNumBetween_1'] = '';
        }
      });
    },

    /* 筛选项不可选设置 */
    initDisabled() {
      let arrSetting = this.arrSetting;

      for (let i = 0; i < this.levelOneOpts.length; i++) {
        let item = this.levelOneOpts[i];

        this.levelOneOpts[i]['isDisabled'] = false;

        for (let j = 0; j < arrSetting.length; j++) {
          let cItem = arrSetting[j];

          if (this.levelOneOpts[i]['isDisabled']) {
            continue;
          }

          if (item.name === cItem.name) {
            this.levelOneOpts[i]['isDisabled'] = true;
          }
        }
      }
    },

    /* 根据父级 data type 返回子级下拉选项 */
    getDataTypeOpts(i) {
      let dataType = this.arrSetting[i].dataType;

      let objKey = {
        'string': 'textOpts',
        'number': 'numberOpts',
        'bool': 'boolOpts',
        'datetime': 'datetimeOpts',
        'list': 'listOpts',
      };

      if (objKey[dataType]) {
        return this[objKey[dataType]];
      }

      return [];
    },

    /* 返回计算线条高度 */
    getLineHeight() {
      let len = this.arrSetting.length;

      if (len < 2) {
        return 0;
      }
      if (len === 2) {
        return '38px';
      }
      return ((len - 2) * 38 + 38) + 'px';
    },

    getParams(item) {
      let objMap = DataTypeConfig.rules;  //显示组件

      for (let key in objMap) {
        let obj = objMap[key];

        let arr1 = obj.dataTypeArr;
        let arr2 = obj.newDataTypeArr;

        if (arr1.indexOf(item.dataType) >= 0 && arr2.indexOf(item['new_data_type'].key) >= 0) {
          if (typeof obj.key === 'string') {
            return item[obj.key];
          }

          let arr3 = [];
          for (let i = 0; i < obj.key.length; i++) {
            let k = obj.key[i];

            if (item[k].key) {
              arr3.push(item[k].key);
            } else {
              arr3.push(item[k]);
            }
          }

          return arr3;
        }
      }

      return false;
    },

    /* 返回自定义筛选项 */
    getFilterConditions() {
      let arr = [];
      let arrSetting = this.arrSetting;

      if (!arrSetting || arrSetting.length === 0) {
        return {};
      }

      for (let i = 0; i < arrSetting.length; i++) {
        let item = arrSetting[i];

        if (!item.name || !item['new_data_type'] || !item['new_data_type'].key) {
          return false;
        }

        let param = {};
        if (this.isEvent) {
          if (this.supName.indexOf(',') > -1) {
            param = {
              "field": 'event._Anything.' + item.name,
              "function": item['new_data_type'].key,
            }
          } else {
            param = {
              "field": 'event.' + this.supName + '.' + item.name,
              "function": item['new_data_type'].key,
            }
          }
        } else {
            param = {
              "field": 'user.' + item.name,
              "function": item['new_data_type'].key,
            }
          }


        let params = this.getParams(item);
        if (params) {
          param['params'] = params;
        }

        arr.push(param);
      }

      if (arrSetting.length === 1) {
        return {conditions: arr};
      }

      return {
        conditions: arr,
        relation: this.relation.key,       // 且 | 或
      }
    },

    /* 获取一级下拉菜单选项（默认） */
    getFunnelCondition() {
      let t = this;

      /* 如果需要父级，却没有传父级，不需要调用接口 */
      if (t.isSupName && !t.supName) {
        return;
      }

      let type_ = 'event';
      if (!this.isEvent) {
        type_ = 'user';
      }

      let param = {
        req:{
          events: [t.isSupName ? t.supName : '_Anything'],
          type: type_,
          needEventTime: true
        },
        operationCtx: {}
      };

      propertyList(param).then((res) => {
        // 返回状态码如果不是 200，说明数据异常，需弹窗提示
        if (res.status !== 200) {
          this.$alert(res.data.msg, '提示', {type: 'warning'});
          return;
        }

        t.levelOneOpts = res.data.value.list;
        if (t.editArr.conditions.length > 0) {
          t.initData();
        }
      }).catch((error) => {
        console.log('error = ', error);
      });
    },

    /* 通过已选一级的值，获取三级下拉选项 */
    getValueList(i, arr) {
      let t = this;
      let setting = t.arrSetting[i];
      let k = setting.name;

      if (setting.dataType !== 'string') {
        return;
      }


      let field = "";
      if (this.isEvent === true) {
        /* 如果需要父级，却没有传父级，不需要调用接口 */
        if (this.isSupName && this.supName) {
          field = 'event.'+this.supName+'.'+ setting.name
        }else{
          field = 'event._Anything.'+ setting.name
        }
      }else{
        field =  'user.'+setting.name
      }


      let param = {
        req:{
          field: field,
          limit: 10,
          appId: JSON.parse(window.sessionStorage.getItem('appItem')).appId,
          fuzzyStr: ''
        },
        operationCtx: {}
      };
      valueList(param).then((res) => {
        // 返回状态码如果不是 200，说明数据异常，需弹窗提示
        if (res.status !== 200) {
          this.$alert(res.data.msg, '提示', {type: 'warning'});
          return;
        }
        t.lastOptsMap[k] = res.data.value.list;

        if (t.isArray(arr)) {
          t.lastOptsMap[k] = this.MergeArray(t.lastOptsMap[k], arr);
          this.arrSetting[i]['customArr'] = arr;
        }

        t.$forceUpdate();  // 强制刷新组件数据
      })
          .catch((error) => {
            t.lastOptsMap[k] = [];
            console.log('error = ', error);
          });
    },

    isArray(a) {
      return (Object.prototype.toString.call(a) === '[object Array]');
    },

    /* 数组去重 */
    MergeArray(arr1, arr2) {
      let _arr = new Array();

      for (let i = 0; i < arr1.length; i++) {
        _arr.push(arr1[i]);
      }

      for (let i = 0; i < arr2.length; i++) {
        let flag = true;

        for (let j = 0; j < arr1.length; j++) {
          if (arr2[i] == arr1[j]) {
            flag = false;
            break;
          }
        }

        if (flag) {
          _arr.push(arr2[i]);
        }
      }

      return _arr;
    },

  },

}
</script>


<style scoped lang="scss">
.viewFunnelBox {
  padding: 10px 0;
  border-bottom: 1px solid #e7e7e7;
  position: relative;

  button {
    height: 27px;
  }

  .title-size {
    display: inline-block;
    width: 80px;
    padding: 0 10px;
    text-align: right;
  }

  .el-select {
    margin-right: 10px;
  }
}

.funnelSettingBox {
  border-left: 2px solid #6FD3B3;
  padding: 5px 0 5px 97px;
  position: relative;

  &:hover {
    background-color: #fafafa;
  }

  input[type='number'] {
    padding-right: 0;
  }

  .el-select {
    margin-right: 10px;
  }

  .size {
    padding-right: 5px;
  }

  .betweenBox,
  .datetimeBox {
    display: inline-block;
  }
}

i.el-icon-delete {
  position: absolute;
  right: 20px;
  top: 50%;
  transform: translate(0, -50%);
  cursor: pointer;

  &:hover {
    color: rgb(247, 86, 94);
  }
}

.andOrNotBox,
.lineBox {
  position: absolute;
  top: 50%;
}

/* 且或非 */
.andOrNotBox {
  width: 26px;
  height: 26px;
  font-size: 12px;
  text-align: center;
  line-height: 26px;
  border: 1px solid #cccccc;
  background-color: #fafafa;
  border-radius: 3px;
  cursor: pointer;
  z-index: 10;
  transform: translate(46px, -50%);
}

.lineBox {
  width: 26px;
  border: 1px solid #cccccc;
  border-right: none;
  transform: translate(60px, -50%);
  z-index: 5;
}
</style>
